import logging
import os

from oriolus.pith.archivers.zip import ZipArchiver
from oriolus.pith.packets.cryptography import Cryptography, CryptographyError
from oriolus.pith.packets.hashwriter import  HashFileWriter, Strategy, Visitor
from oriolus.pith.packets.metareader import FileMetaReader

class Packer:
    def __init__(self, output_path = None, keyring = None, key_id = None):
        self.logger = logging.getLogger("Packer")
        if output_path:
            self.output_path = output_path
        else:
            self.output_path = "."
            
        if not os.path.isdir(self.output_path):
            os.makedirs(self.output_path)
            
        self.keyring = keyring
        self.key_id = key_id
        
    def pack(self, input_path):
        if self.check_input_path(input_path):
            archiver = ZipArchiver()
            packet_name = self.get_filename(input_path)
            full_packet_name = os.path.join(self.output_path, packet_name)
            self.write_checksums(input_path)
            archiver.archive(input_path, full_packet_name)
            
            return full_packet_name
        else:
            self.logger.error("Incorrect data in input directory.")
            
            return None

    def pack_and_sign(self, input_path, key_password, secret_keyring=None):
        full_packet_name = self.pack(input_path)
        
        if full_packet_name:
            crypto = Cryptography(keyring = self.keyring)
            try:
                if secret_keyring:
                    crypto.create_signature_by_keyring(full_packet_name, secret_keyring, key_password, local_user=self.key_id)
                elif key_password != None:
                    crypto.create_signature_by_default_keyring(full_packet_name, key_password, local_user=self.key_id)
                else:
                    crypto.create_signature(full_packet_name, local_user=self.key_id)
                    
            except CryptographyError:
                self.logger.error("Cryptography error was raised.")
                
                return False
                
            return True
        else:
            return False
            
    def check_input_path(self, input_path):
        if os.path.exists(input_path):
            data_path = os.path.join(input_path, "data")
            scripts_path = os.path.join(input_path, "scripts")
            meta_path = os.path.join(input_path, "META")
            if os.path.isdir(data_path) and os.path.isdir(scripts_path) and os.path.isfile(meta_path):
                if os.path.isfile(os.path.join(scripts_path, "install.py")) and os.path.isfile(os.path.join(scripts_path, "remove.py")):
                    return True
        
        return False
        
    def get_filename(self, input_path):
        meta_filename = os.path.join(input_path, "META")
        meta = FileMetaReader().read(meta_filename)
        
        return "%s-%s.zip.ori" % (meta.name, meta.version)

    def write_checksums(self, input_path):
        checksums_filename = os.path.join(input_path, "CHECKSUMS")
        
        if os.path.isfile(checksums_filename):
            os.remove(checksums_filename)
        
        visitor = Visitor(input_path)
        strategy = Strategy()
        dict = visitor.list(strategy.get_file_hash)

        writer = HashFileWriter(checksums_filename)
        writer.write_strings(dict)
